/*
如何代理一个Object
1. 首先考虑读取操作
-- 直接读取属性 obj.foo
-- in判断属性是否存在于对象或其原型上  'foo' in obj
-- for..in..遍历  for(const key in obj)
*/

import {
  effect,
  track,
  trigger,
  ITERATE_KEY,
  TriggerType,
} from './reactive-system'

const obj = { foo: 1 }

const p = new Proxy(obj, {
  // in 操作的拦截
  has(target, key) {
    // console.log('拦截 in 操作')
    track(target, key)
    return Reflect.has(target, key)
  },
  // for... in ...拦截
  ownKeys(target) {
    // console.log('拦截for...in...')
    track(target, ITERATE_KEY)
    return Reflect.ownKeys(target)
  },
  set(target, key, val, receiver) {
    const type = Object.prototype.hasOwnProperty.call(target, key)
      ? TriggerType.SET
      : TriggerType.ADD // 要区分是新增属性还是修改属性
    const res = Reflect.set(target, key, val, receiver)
    trigger(target, key, type)
    return res
  },
  // 拦截删除属性操作
  deleteProperty(target, key) {
    const hasKey = Object.prototype.hasOwnProperty.call(target, key) // 判断是否是自身属性
    const res = Reflect.deleteProperty(target, key)
    if (res && hasKey) {
      trigger(target, key, TriggerType.DELETE)
    }
    return res
  },
})

effect(() => {
  console.log('test "in" statement', 'foo' in p)
})

effect(() => {
  console.log('for...in... effects')
  for (const key in p) {
    console.log(key)
  }
})

p.bar = 2
p.bar++

/*
关于对象的代理，还剩下最后的工作， 即删除对象的属性
Proxy的delete操作符行为依赖是deleteProperty
*/

delete p.bar
